var utils = require('./utils.js');
var generalRequest = require('./request.js');
var async = require('async');

/**
 * 获取bucket下的objects
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.delimiter           分隔符，用于对一组参数进行分割的字符,非必须
 *     @params  {String}  params['encoding-type']    前缀匹配，用来规定返回的文件前缀地址，非必须
 *     @params  {String}  params.marker              指定列举指定空间中对象的起始位置。KS3按照字母排序方式返回结果，将从给定的 marker 开始返回列表。如果相应内容中IsTruncated为true，则可以使用返回的Contents中的最后一个key作为下次list的marker参数，非必须
 *     @params  {String}  params['max-keys']         设置响应体中返回的最大记录数（最后实际返回可能小于该值）。默认为1000。如果你想要的结果在1000条以后，你可以设定 marker 的值来调整起始位置，非必须
 *     @params  {String}  params.prefix              限定响应结果列表使用的前缀，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */

async function listObjects(params){
    var headers = params.headers || {};
    var urlParams = {
        delimiter: params['delimiter'],
        'encoding-type': params['encoding-type'],
        marker: params['marker'],
        'max-keys': params['max-keys'],
        prefix: params['prefix']
    };
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region
    })

    var reqParams = {
        method: 'GET',
        bucket,
        url,
        qs: urlParams,
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, '', '', reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 获取object的元数据
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */
 async function headObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }

    var headers = params.headers || {};
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })

    var reqParams = {
        method: 'HEAD',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 获取指定object
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.range               range(用于请求资源的部分内容，单位是byte)，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */
async function getObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }

    var headers = params.headers || {};
    if(params.range){
        headers['Range'] = params.range;
    }
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })

    var reqParams = {
        method: 'GET',
        bucket,
        url,
        qs: {},
        headers: headers,
        responseType: 'blob',
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '',reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.method              请求方法，PUT/GET/POST/DELETE，非必须
 *     @params  {String}  params.expires             签名几秒后失效，默认900秒，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */
function getObjectUrl(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }

    var headers = params.headers || {};
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })

    var expires = params.expires || 15*60;
    // 时间戳精确到秒
    var expirationTime = (new Date().getTime() + expires * 1000).toString().substr(0,10);
    var reqParams = {
        method: params.method || 'GET',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, expirationTime);
    url = `${url}?KSSAccessKeyId=${this.config.AK}&Expires=${expirationTime}&Signature=${encodeURIComponent(signature)}`
    var promise = new Promise((resolve) => {
        resolve(url)
    });
    return promise;
}

/**
 * 删除指定object
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 */
async function delObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }

    var headers = params.headers || {};
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })

    var reqParams = {
        method: 'DELETE',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * @params  {Object}  params                           参数对象，必须
 *     @params  {String}    params.bucket              bucket名称，非必须
 *     @params  {String}    params.key                 object key，必须
 *     @params  {String}    params.region              region名称，非必须
 *     @params  {String}    params.acl                 文件预设ACL(private | public-read)，默认值private，非必须
 *     @params  {String}    params.file                上传的文件，非必须
 *     @params  {Boolean}   params.encryption          是否加密文件，非必须
 *     @params  {String}    params.storageClass        对象的存储类型,非必须，如果Bucket是归档类型，当不指定storageClass时，Object自动为归档类型，如果Bucket是非归档类型，Object自动为标准类型
 *     @params  {Function}  params.progress            上传进度监听函数，非必须
 *     @params  {String}    params.signature           请求签名(从服务端获取)，非必须
 *     @params  {String}    params.headers             自定义header信息，非必须
 */
async function putObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    // if (params.file === null || params.file === undefined) {
    //     throw Error('require the params of file!');
    //     return;
    // }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    var headers = params.headers || {};
    if (!headers['Content-Type'] && !headers['content-type']) {
        headers['Content-Type'] = (params.file && params.file.type) ? params.file.type : '';
    } 
    if(params.acl){
        if(['private','public-read'].indexOf(params.acl)==-1){
            throw Error('The value of acl can only be private or public-read!');
        }
        headers['x-kss-acl'] = params.acl;
    }
    if(params.encryption){
        headers['x-kss-server-side-encryption'] = 'AES256';
    }
    if(params.storageClass){
        headers['x-kss-storage-class'] = params.storageClass;
    }
    var onProgress = utils.throttleOnProgress.call(this, 0, params.progress);
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })
    var reqParams = {
        method: 'PUT',
        bucket,
        url,
        qs: {},
        headers: headers,
        body: params.file,
        onProgress
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    if (params.authorization) {
        reqParams.headers['Authorization'] = params.authorization;
    }
    return await generalRequest.bind(this)(reqParams);
}


/**
 * @params  {Object}  params                           参数对象，必须
 *     @params  {String}    params.bucket              bucket名称，非必须
 *     @params  {String}    params.key                 object key，必须
 *     @params  {String}    params.region              region名称，非必须
 *     @params  {String}    params.acl                 文件预设ACL(private | public-read)，默认值private，非必须
 *     @params  {String}    params.file                上传的文件，非必须
 *     @params  {Boolean}   params.encryption          是否加密文件，非必须
 *     @params  {String}    params.storageClass        对象的存储类型,非必须，如果Bucket是归档类型，当不指定storageClass时，Object自动为归档类型，如果Bucket是非归档类型，Object自动为标准类型
 *     @params  {Function}  params.progress            上传进度监听函数，非必须
 *     @params  {String}    params.signature           请求签名，非必须
 *     @params  {String}    params.headers             自定义header信息，非必须
 */
async function appendObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    var headers = params.headers || {};
    if (!headers['Content-Type'] && !headers['content-type']) {
        headers['Content-Type'] = (params.file && params.file.type) ? params.file.type : '';
    } 
    if(params.acl){
        if(['private','public-read'].indexOf(params.acl)==-1){
            throw Error('The value of acl can only be private or public-read!');
        }
        headers['x-kss-acl'] = params.acl;
    }
    if(params.encryption){
        headers['x-kss-server-side-encryption'] = 'AES256';
    }
    if(params.storageClass){
        headers['x-kss-storage-class'] = params.storageClass;
    }
    if(params.position === null || params.position === undefined || Number(params.position)< 0){
        throw Error('require the params of position!');
    }
    var onProgress = utils.throttleOnProgress.call(this, 0, params.progress);
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var resource = `?append&position=${params.position}`;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var reqParams = {
        method: 'POST',
        bucket,
        url,
        qs: {},
        headers: headers,
        body: params.file,
        onProgress
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    if (params.authorization) {
        reqParams.headers['Authorization'] = params.authorization;
    }
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 解冻指定object
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 */
async function restoreObject(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }
    var resource = '?restore';
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var headers = params.headers || {};

    var reqParams = {
        method: 'POST',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 获取object ACL
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */
 async function getObjectAcl(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }
    var resource = '?acl';
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var headers = params.headers || {};
    var reqParams = {
        method: 'GET',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 设置object ACL
 * @params  {Object}  params                         参数对象，必须
 *     @params  {String}  params.bucket              bucket名称，非必须
 *     @params  {String}  params.key                 object key，必须
 *     @params  {String}  params.region              region名称，非必须
 *     @params  {String}  params.acl                 acl，有效值（private, public-read），必须
 *     @params  {Object}  params.headers             自定义header信息，非必须
 *     @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 */
 async function putObjectAcl(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or this.config of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or this.config of region!');
    }
    if(params.acl !== 'private' && params.acl !== 'public-read'){
        throw Error('The value of acl can only be private or public-read!');
    }
    var headers = params.headers || {};
    var resource = `?acl`;
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    if(params.acl){
        headers['x-kss-acl'] = params.acl;
    }
    var reqParams = {
        method: 'PUT',
        bucket,
        url,
        qs: {},
        headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 大文件拷贝
 * 
 * @params  {Object}  params                                参数对象，必须
 *     @params  {String}  params.bucket                     bucket名称，非必须
 *     @params  {String}  params.key                        目标文件URL绝对路径，必须
 *     @params  {String}  params.sourceBucket               源文件URL绝对路径,例如：test-bucket/test.jpeg，必须
 *     @params  {String}  params.sourceKey                  源bucket名称，必须
 *     @params  {Function}  params.progress                 上传进度监听函数，非必须
 *     @params  {Boolean}  params.encryption                是否加密文件，非必须
 *     @params  {Object}  params.headers                    自定义header信息，非必须
 *     @params  {String}  params.signature                  请求签名(从服务端获取)，非必须
 * 
 * @params {*} cb 
 *    @return  {Object}  res                           请求结果
 */
async function uploadPartCopy (params, cb) {
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.sourceKey){
        throw Error('require the params of sourceKey!');
    }
    if(!params.sourceBucket){
        throw Error('require the params of sourceBucket!');
    }
    if(!params.key){
        throw Error('require the params of key!');
    }
    let self = this;
    return await headObject.bind(self)({ 
        'key': params.sourceKey,
        'bucket': params.sourceBucket,
    }).then(res => {
        if(res.statusCode === 200){
            var size = 0;
            size = Number(res.headers['content-length'] ? res.headers['content-length'] : 0);
            params.uploadType = 'copyPart';
            params.file = {size};
            self.uploadMultiPart(params, cb);
        }else{
            throw Error('This key does not exist !');
        }
    })
}

/**
 * 复制小文件
 * 
 * @params  {Object}  params                                参数对象，必须
 *     @params  {String}  params.bucket                     bucket名称，非必须
 *     @params  {String}  params.key                        目标文件URL绝对路径，必须
 *     @params  {String}  params.sourceBucket               源文件URL绝对路径,例如：test-bucket/test.jpeg，必须
 *     @params  {String}  params.sourceKey                  源bucket名称，必须
 *     @params  {String}  params.storageClass               对象的存储类型,非必须，如果Bucket是归档类型，当不指定storageClass时，Object自动为归档类型，如果Bucket是非归档类型，Object自动为标准类型
 *     @params  {Boolean} params.encryption                 是否加密文件，非必须 (如果源文件进行过加密，copy时目标文件也要进行加密)
 *     @params  {Object}  params.headers                    自定义header信息，非必须
 *     @params  {Function}params.progress                   上传进度监听函数，非必须
 *     @params  {String}  params.signature                  请求签名(从服务端获取)，非必须
 * 
 */
async function putObjectCopy(params) {
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.sourceKey){
        throw Error('require the params of sourceKey!');
    }
    if(!params.sourceBucket){
        throw Error('require the params of sourceBucket!');
    }
    if(!params.key) {
        throw Error('require the params of key!');
    }
    var headers = {};
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var contentType = params['content-type'] || '';
    headers['x-kss-metadata-directive'] = 'COPY';
    headers['x-kss-copy-source'] = '/' + params.sourceBucket + '/' + encodeURIComponent(params.sourceKey);
    if(params.storageClass){
        headers['x-kss-storage-class'] = params.storageClass;
    }
    if(params.encryption){
        headers['x-kss-server-side-encryption'] = 'AES256';
    }
    headers = Object.assign(headers, params.headers);
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key
    })
    var reqParams = {
        method: 'PUT',
        bucket,
        url,
        qs: {},
        headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * post方式上传文件
 * @params  {Object}  params                         参数对象，必须
 *       @params  {FormData}  params.formData
 *          @params  {String}  key                   object的key，必须
 *          @params  {String}  file                  上传的文件，必须
 *          @params  {String}  acl                   acl，有效值（private, public-read），非必须
 *          @params  {String}  KSSAccessKeyId        AK，非必须
 *          @params  {String}  signature             请求签名，非必须
 *          @params  {String}  policy                policy，非必须
 *      @params  {Object}  params.headers            自定义header信息，非必须
 *      @params  {String}  params.bucket             bucket名称，非必须
 * - formData: { KSSAccessKeyId, key, Policy, signature, file, ... }
 * - KSSAccessKeyId, key, signature, file必填
 */
async function postObject (params) {
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(!params.formData) {
        throw Error('require the params of formData!');
    }
    var formData = params.formData;
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var headers = params.headers || {};

    var url = getUrl.bind(this)({
        bucket,
        region
    })
    if (formData.get('policy')) {
        var policy = JSON.parse(formData.get('policy'))
        formData.set('policy', utils.getStrBase64(policy));
        formData.set('signature', formData.get('signature') || utils.getPostSignature(this.config.SK, policy));
        formData.set('KSSAccessKeyId', formData.get('KSSAccessKeyId') || this.config.AK)
    }
    //表单上传时，file必须为表单的最后一项
    if (formData.get('file')) {
        var file = formData.get('file');
        formData.delete('file');
        formData.append('file', file);
    }
    var reqParams = {
        method: 'POST',
        bucket,
        url,
        headers: headers,
        body: formData
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    if (!formData.get('policy')) {
        var signature = utils.getAuth(this.config.SK, reqParams.bucket, formData.get('key'), '', reqParams.method, reqParams.headers, reqParams.date);
        reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    }
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 分块上传相关---全流程
 * @params  {Object}  params                        参数对象，必须
 *    @params  {String}  params.bucket              bucket名称，非必须
 *    @params  {String}  params.key                 object key，必须
 *    @params  {String}  params.region              region名称，非必须
 *    @params  {String}  params.acl                 文件预设ACL(private | public-read)，默认值private，非必须
 *    @params  {String}  params.file                上传的文件，必须
 *    @params  {Function}params.progress            上传进度监听函数，非必须
 *    @params  {String}  params.parallelLimit       分块请求的最大并发数，默认为10，非必须
 *    @params  {String}  params.retries             分块请求失败重试次数，默认为2，非必须
 *    @params  {Boolean} params.encryption          是否使用服务端加密，仅支持"AES256"加密，非必须
 *    @params  {String}  params.uploadType          'upload'大文件上传 / 'copyPart'大文件复制，默认upload，非必须
 *    @params  {Object}  params.headers             自定义header信息，非必须
 *    @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 * @params {*} cb 
 *    @return  {Object}  res                           请求结果
 */
 function uploadMultiPart(params, cb){
    if ((params.file === null || params.file === undefined) && params.uploadType !== 'copyPart') {
        throw Error('require the params of file!');
    }
    let self = this;
    // 每个块的上传进度数组
    let uploadArr = [];
    let timer = null;
    async.auto({
        // 初始化分块上传
        uploadId:  function (callback) {
            self.initiateMultipartUpload({
                bucket: params.bucket,
                file: params.file,
                encryption: params.encryption,
                key: params.key,
                acl: params.acl,
                headers: params.headers
            }).then(res => {
                if(res && res.statusCode === 200){
                    if (res.body && res.body.InitiateMultipartUploadResult) {
                        var uploadId = res.body.InitiateMultipartUploadResult.UploadId;
                        callback(null, uploadId);
                    }
                }else{
                    callback(res.error ? res : '');
                }
            });
        },
        sliceList: ['uploadId', function(results, callback){
            // 获取文件大小
            var totalSize = params.file.size;
            // 控制分块大小
            var chunkSize = self.config.chunkSize;
            var chunkNum = Math.ceil(totalSize/chunkSize);
            // 存放分片后的数据
            var sliceList = [];
            // 初始化进度数组
            uploadArr = new Array(chunkNum).fill(0);
            // 总进度
            let uploadSize = 0;
            // 进度参数存在
            if (params.progress) {
                // 设置定时器
                timer = setInterval(() => {
                    // 计算已上传的文件大小
                    uploadSize = uploadArr.reduce((pre, cur) => pre + cur, 0);
                    // 最终进度
                    params.progress({
                        percent: (uploadSize / totalSize).toFixed(2),
                        uploadId: results.uploadId
                    });
                }, self.config.progressInterval);
            }
            // 上传的分片数据
            for(let i = 1; i <= chunkNum; i++){
                // 给文件分块
                var endSize = i == chunkNum ? totalSize : chunkSize * i;
                if(params.uploadType === 'copyPart'){
                    //大文件拷贝
                    sliceList.push({
                        key: params.key,
                        partNumber: i,
                        uploadId: results.uploadId,
                        range: 'bytes=' + chunkSize * (i - 1)+ '-' + endSize,
                        uploadType: 'copyPart',
                        sourceKey: params.sourceKey,
                        sourceBucket: params.sourceBucket,
                        bucket: params.bucket,
                        progress: (e) => {
                            uploadArr[i - 1] = e.loaded;
                        }
                    })
                    if(sliceList.length === chunkNum){
                        console.log('sliceList:', sliceList);
                        callback(null, sliceList);
                    }
                }else{
                    //大文件上传
                    sliceList.push({
                        key: params.key,
                        partNumber: i,
                        uploadId: results.uploadId,
                        uploadType: 'upload',
                        bucket: params.bucket,
                        progress: (e) => {
                            uploadArr[i - 1] = e.loaded;
                        },
                        start:chunkSize*(i-1),
                        end: endSize
                    })
                    if(sliceList.length === chunkNum){
                        console.log('sliceList:', sliceList);
                        callback(null, sliceList);
                    }
                }
            };
        }],
        uploadPartList: ['sliceList', function (results, callback) {
            var uploadPartList = [];
            // 上传控制并发数
            var limit = params.parallelLimit || self.config.parallelLimit;
            // 失败重试次数
            var retryTimes = params.retryTimes || self.config.retryTimes;
            // 上传分块
            async.eachLimit(results.sliceList, limit, function(sliceItem, callback){
                async.retry(retryTimes, function (tryCallback) {
                    if(params.uploadType === 'copyPart') {
                        self.uploadPart(sliceItem).then(res => {
                            console.log(res)
                            console.log('正在上传第'+ sliceItem.partNumber +'块!');
                            if(!res.error){
                                uploadPartList.push({
                                    partNumber: sliceItem.partNumber,
                                    etag: res.headers.etag
                                });
                            }
                            tryCallback(res.error ? res : '', res);
                        })
                    } else {
                        utils.fileSlice(params.file, sliceItem.start, sliceItem.end, function(result) {
                            let item = {
                                key: sliceItem.key,
                                partNumber: sliceItem.partNumber,
                                body: result,
                                uploadId: sliceItem.uploadId,
                                uploadType: sliceItem.uploadType,
                                bucket: sliceItem.bucket,
                                progress: sliceItem.progress,
                            }
                            self.uploadPart(item).then(res => {
                                console.log(res)
                                console.log('正在上传第'+ item.partNumber +'块!');
                                if(!res.error){
                                    uploadPartList.push({
                                        partNumber: item.partNumber,
                                        etag: res.headers.etag
                                    });
                                }
                                tryCallback(res.error ? res : '', res);
                            })
                        })
                    }
                }, function (err, res) {
                    console.log('retry result:',err, res);
                    callback(err, res)
                });
            }, 
            function(err){
                console.log('迭代器结束或出现一个err:', err);
                clearInterval(timer);
                if(err){
                    callback(err);
                }else{
                    callback(null, uploadPartList);
                }
            })
        }],
        complete: ['uploadPartList', function (results, callback) {
            // 清除定时器
            clearInterval(timer);
            console.log('results:', results);
            var partList = results.uploadPartList;
            // 合并上传的分块
            self.completeMultipart({
                key: params.key,
                parts: partList,
                uploadId: results.uploadId,
                uploadType: params.uploadType === 'copyPart' ? 'copyPart' : 'upload'
            }).then(res => {
                callback(res.error ? res : '',res);
            })
        }]
    }, function(err, res) {
        var result = {};
        if(err){
            result = err;
        }else{
            result = res.complete;
        }
        cb(result);
    });
}

/**
 * 分块上传相关---初始化分块上传
 * @params  {Object}  params                        参数对象，必须
 *    @params  {String}  params.bucket              bucket名称，非必须
 *    @params  {String}  params.key                 object key，必须
 *    @params  {String}  params.region              region名称，非必须
 *    @params  {String}  params.acl                 文件预设ACL(private | public-read)，默认值private，非必须
 *    @params  {String}  params.storageClass        存储类型，非必须，如果Bucket是归档类型，当不指定storageClass时，Object自动为归档类型，如果Bucket是非归档类型，Object自动为标准类型
 *    @params  {Boolean} params.encryption          是否使用服务端加密，仅支持"AES256"加密，非必须
 *    @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers             自定义header信息，非必须
 */
async function initiateMultipartUpload(params){
    var headers = {};
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(params.acl){
        if(['private','public-read'].indexOf(params.acl)===-1){
            throw Error('The value of acl can only be private or public-read!');
        }
        headers['x-kss-acl'] = params.acl;
    }
    if(params.encryption){
        headers['x-kss-server-side-encryption'] = 'AES256';
    }
    if(params.storageClass){
        headers['x-kss-storage-class'] = params.storageClass;
    }
    headers = Object.assign(headers, params.headers);
    var resource = '?uploads'
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var reqParams = {
        method: 'POST',
        bucket,
        url,
        qs: {},
        headers: headers
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 分块上传相关---上传文件块
 * @params  {Object}  params                             参数对象，必须
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.key                      object key，必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {File || Blob || String}  params.body     分块数据，上传文件对象或字符串，必须
 *    @params  {String}  params.partNumber               分块的序号，必须
 *    @params  {String}  params.uploadId                 初始化分块上传时获取的上传id，必须
 *    @params  {Function}  params.progress               上传进度监听函数，非必须
 *    @params  {String}  params.signature                请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */
 async function uploadPart(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(!params.partNumber){
        throw Error('require the params of partNumber!');
    }
    if(!params.uploadId){
        throw Error('require the params of uploadId!');
    }
    var headers = {};
    if(params.uploadType === 'copyPart'){
        headers['x-kss-copy-source'] = '/' + params.sourceBucket + '/' + utils.encodeKey(params.sourceKey);
        headers['x-kss-copy-source-range'] = params.range;
    }
    headers = Object.assign(headers, params.headers);
    var resource = `?partNumber=${params.partNumber}&uploadId=${params.uploadId}`;
    var bucket = params.bucket  || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var onProgress = utils.throttleOnProgress.call(this, 0, params.progress);
    var reqParams = {
        method: 'PUT',
        bucket,
        url,
        qs: {},
        headers: headers,
        onProgress
    }
    if(params.uploadType === 'upload'){
        reqParams.body = params.body
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key , resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 分块上传相关---完成分块上传后，合并分块
 * @params  {Object}  params                             参数对象，必须
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.key                      object key，必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {Array}   params.parts                    分块信息列表，必须
 *       @params  {String}  params.parts[i].partNumber      块编号，必须
 *       @params  {String}  params.parts[i].etag            分块的 sha1 校验值，必须
 *    @params  {String}  params.uploadId                 初始化分块上传时获取的上传id，必须
 *    @params  {String}  params.signature                请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */

async function completeMultipart(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(!params.uploadId){
        throw Error('require the params of uploadId!');
    }
    if(!params.parts || !params.parts.length){
        throw Error('require the params of parts!');
    }
    var headers = {};
    headers = Object.assign({
        'content-type': 'text/plain;charset=UTF-8'
    }, params.headers);
    var resource = `?uploadId=${params.uploadId}`;
    var body = utils.generateCompleteXML(params.parts)
    var region = params.region || this.config.region;
    var bucket = params.bucket || this.config.bucket;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var reqParams = {
        method: 'POST',
        bucket,
        url,
        qs: {},
        headers: headers,
        body
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 列出指定上传任务中所有已上传的块
 * @params  {Object}  params                             参数对象，必须
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.key                      object key，必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {String}  params.uploadId                 初始化分块上传时获取的上传id，必须
 *    @params  {String}  params.max-parts                 设置响应体中块的最大数量(默认值: 1000)，非必须
 *    @params  {String}  params.part-number-marker         指定应该从哪个块开始列举(只有比设定值大的块才会被列举)，非必须
 *    @params  {String}  params.signature                请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */
async function listParts(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(!params.uploadId){
        throw Error('require the params of uploadId!');
    }
    var headers = params.headers || {};
    var resource = `?uploadId=${params.uploadId}`;
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var qs = {};
    if(params['max-parts']){
        qs['max-parts'] = params['max-parts'];
    }
    if(params['part-number-marker']){
        qs['part-number-marker'] = params['part-number-marker'];
    }
    if(params['encoding-type']){
        qs['encoding-type'] = params['encoding-type'];
    }
    var reqParams = {
        method: 'GET',
        bucket,
        url,
        qs,
        headers: headers,
        body: {}
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 取消已上传的块
 * @params  {Object}  params                             参数对象，必须 
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.key                      object key，必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {String}  params.uploadId                 初始化分块上传时获取的上传id，必须
 *    @params  {String}  params.signature                请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */
async function abortMultipartUpload(params){
    if (params.key === null || params.key === undefined) {
        throw Error('require the params of key!');
    }
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    if(!params.uploadId){
        throw Error('require the params of uploadId!');
    }
    var headers = params.headers || {};
    var resource = `?uploadId=${params.uploadId}`;
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        key: params.key,
        resource
    })
    var reqParams = {
        method: 'DELETE',
        bucket,
        url,
        qs: {},
        headers: headers,
        body: params.body
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 查看正在进行的分块上传任务
 * @params  {Object}  params                             参数对象，必须
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {Integer} params['max-uploads']           限定要列出正在进行任务的上限值([1,1000])，默认1000，非必须
 *    @params  {String}  params['upload-id-marker']      与key-marker配合使用，指定列举目标空间中正在进行分块上传任务的起始位置，非必须
 *    @params  {String}  params['key-marker']            与upload-id-marker配合使用，指定列举目标空间中正在进行分块上传任务的起始位置，非必须
 *    @params  {String}  params['encoding-type']         指明请求KS3与KS3响应使用的编码方式。object key 可以包含任意Unicode字符，非必须
 *    @params  {String}  params.prefix                   限定响应结果列表使用的前缀，正如你在电脑中使用的文件夹一样，非必须
 *    @params  {String}  params.signature                请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */
async function listMultipartUploads(params){
    if(!params.bucket && !this.config.bucket){
        throw Error('require the params of bucket or defaultConfig of bucket!');
    }
    if(!params.region && !this.config.region){
        throw Error('require the params of region or defaultConfig of region!');
    }
    var headers = params.headers || {};
    var qs = {};
    if(params['max-uploads']){
        qs['max-uploads'] = params['max-uploads'];
    }
    if(params['upload-id-marker']){
        qs['upload-id-marker'] = params['upload-id-marker'];
    }
    if(params['key-marker']){
        qs['key-markers'] = params['key-marker'];
    }
    if(params['encoding-type']){
        qs['encoding-type'] = params['encoding-type'];
    }
    if(params.prefix){
        qs.prefix = params.prefix;
    }
    var resource = '?uploads';
    var bucket = params.bucket || this.config.bucket;
    var region = params.region || this.config.region;
    var url = getUrl.bind(this)({
        bucket,
        region,
        resource
    })
    var reqParams = {
        method: 'GET',
        bucket,
        url,
        qs,
        headers: headers,
        body: {}
    }
    if(!reqParams.headers['x-kss-date']) {
        reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
    }
    reqParams.date = reqParams.headers['x-kss-date'];
    var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, '', resource, reqParams.method, reqParams.headers, reqParams.date);
    reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`;
    return await generalRequest.bind(this)(reqParams);
}

/**
 * 修改object 存储类型
 * @params  {Object}  params                        参数对象，必须
 *    @params  {String}  params.bucket              bucket名称，非必须
 *    @params  {String}  params.key                 object key，必须
 *    @params  {String}  params.region              region名称，非必须
 *    @params  {String}  params.storageClass        存储类型， 必须
 *    @params  {String}  params.signature           请求签名(从服务端获取)，非必须
 *    @params  {Object}  params.headers             自定义header信息，非必须
*/
async function modifyStorageClass(params){
    if(!params.storageClass){
        throw Error('require the params of storageClass!');
    }
    var self = this;
    //确认object是否存在
    return await self.headObject(params).then(res => {
        if(res && res.statusCode === 200){
            var bucket = params.bucket || self.config.bucket;
            var region = params.region || self.config.region;
            var headers = Object.assign({
                'x-kss-copy-source': '/' + bucket + '/' + utils.encodeKey(params.key),
                'x-kss-storage-class': params.storageClass,
                'x-kss-metadata-directive': 'COPY'
            }, params.headers);
            var url = getUrl.bind(self)({
                bucket,
                region,
                key: params.key
            })
            var reqParams = {
                method: 'PUT',
                bucket,
                url,
                qs: {},
                headers: headers,
            }
            if(!reqParams.headers['x-kss-date']) {
                reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString();
            }
            reqParams.date = reqParams.headers['x-kss-date'];
            var signature = params.signature || utils.getAuth(self.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date);
            reqParams.headers['Authorization'] = `KSS ${self.config.AK}:${signature}`;
            return generalRequest.bind(self)(reqParams);
        }else{
            throw Error('This key does not exist !');
        }
    })
}

/**
 * @params  {Object}  params                             参数对象，必须
 *    @params  {String}  params.bucket                   bucket名称，非必须
 *    @params  {String}  params.key                      object key，必须
 *    @params  {String}  params.region                   region名称，非必须
 *    @params  {Number}  params.expiration               expiration，默认为15分钟后过期，非必须
 *    @params  {Object}  params.headers                  自定义header信息，非必须
 */
 function putObjectByPresignedUrl (params) {
    var reqParams = {
        key: params.key,
        expiration: params.expiration || 900,
        method: 'PUT',
        bucket: params.bucket || this.config.bucket
    }
    var url = utils.generatePresignedUrl(reqParams, this.config.SK, this.config.AK, getUrl.bind(this)(reqParams));
    var promise = new Promise((resolve) => {
        resolve(url)
    });
    return promise;
}


/**
 * 获取请求地址 
 * @params {*} params - { region, bucket, domain, resource, protocol, key }
 * @returns 
 * @description
 * -  `${this.config.protocol}://${bucket}.${domain}/${resource}`
 * - resource: key + suffix
 */
 function getUrl(params) {
    var region = params.region || this.config.region;
    var bucket = params.bucket || this.config.bucket;
    var domain = params.domain || '';
    var resource = params.resource || '';
    var key = params.key
    var protocol = params.protocol || this.config.protocol
    if (protocol) {
        protocol += ':'
    } else {
        protocol = location.protocol === 'http' ? 'http:' : 'https:'
    }

    if (!domain) {
        const ENDPOINT_KEY = Object.keys(utils.ENDPOINT)
        if (ENDPOINT_KEY.indexOf(region) > -1) {
            domain = utils.ENDPOINT[region];
        } else {
            // 输入的region不在既定的map中 则设置为默认的domain
            domain = region;
        }
    }else{
        domain = region;
    }

    // 去掉域名最后的斜杆
    if (domain.slice(-1) === '/') {
        domain = domain.slice(0, -1);
    }

    if (!this.config.forcePathStyle) {
        domain = bucket + '.' + domain;
    } else {
        domain = domain + '/' + bucket
    }

    var url = `${protocol}//${domain}`
    if (key) {
        url += `/${utils.encodeKey(key)}`
    }

    if (resource) {
        url += `${resource}`
    }
    console.log('request url: ', url)
    return url;
}




var API_MAP = {
    listObjects,
    headObject,
    getObject,
    getObjectUrl,
    delObject,
    postObject,
    putObject,
    appendObject,
    initiateMultipartUpload,
    uploadPart,
    completeMultipart,
    uploadMultiPart,
    listParts,
    abortMultipartUpload,
    listMultipartUploads,
    uploadPartCopy,
    putObjectByPresignedUrl,
    putObjectCopy,
    restoreObject,
    getObjectAcl,
    putObjectAcl,
    modifyStorageClass,
}
module.exports.methods = API_MAP;
